/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 *																					 *
 * Copyright (c) 2003-2006 by AG-Software											 * 
 * All Rights Reserved.																 *
 *																					 *
 * You should have received a copy of the AG-Software Shared Source License			 *
 * along with this library; if not, email gnauck@ag-software.de to request a copy.   *
 *																					 *
 * For general enquiries, email gnauck@ag-software.de or visit our website at:		 *
 * http://www.ag-software.de														 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

using System;
using System.Text;
using System.Collections;

using agsXMPP.Collections;

namespace agsXMPP
{	
	/// <summary>
	/// Class for building and handling XMPP Id's
	/// </summary>  
    public class Jid : IComparable
#if NET_2 || CF_2
        , IEquatable<Jid>
#endif
	{
		/*		
		14 possible invalid forms of JIDs and some variations on valid JIDs with invalid lengths, viz:

		jidforms = [
			"",
			"@",
			"@/resource",
			"@domain",
			"@domain/",
			"@domain/resource",
			"nodename@",
			"/",
			"nodename@domain/",
			"nodename@/",
			"@/",
			"nodename/",
			"/resource",
			"nodename@/resource",
		]
		*/
		private string m_JID      = null;
		private string m_user     = null;
		private string m_server   = null;
		private string m_resource = null;


		/// <summary>
		/// Create a new JID from a string
		/// </summary>
		/// <param name="jid">XMPP ID, in string form examples: user@server/Resource, user@server</param>
		public Jid(string jid)
		{			
			m_JID = jid;
			Parse(jid);
		}

 
		public bool Parse(string fullJid)
		{
			string user		= null;
			string server	= null;
			string resource = null;

			if (fullJid == null || fullJid.Length == 0)
			{				
				return false;
			}

			m_JID = fullJid;

			int atPos		= m_JID.IndexOf('@');
			int slashPos	= m_JID.IndexOf('/');

			if (atPos == -1)
			{
				user = null;
				if (slashPos == -1)
				{
					// JID Contains only the Server
					server = m_JID;					
				}
				else
				{
					// JID Contains only the Server and Resource
					server = m_JID.Substring(0, slashPos);
					resource = m_JID.Substring(slashPos+1);
				}
			}
			else
			{
				if (slashPos == -1)
				{
					// We have no resource
					// Devide User and Server (user@server)
					server	= m_JID.Substring(atPos + 1);
					user	= m_JID.Substring(0, atPos);					
				}
				else					
				{ 
					// We have all
					user		= m_JID.Substring(0, atPos);
					server		= m_JID.Substring(atPos+1, slashPos-atPos-1);
					resource	= m_JID.Substring(slashPos+1);
				}
			}
			
			this.m_user		= user;
			this.m_server	= server;
			this.m_resource	= resource;

			return true;
		}
		
		public Jid(string user, string server, string resource)
		{
			m_user		= user.ToLower();            
            m_server	= server.ToLower();
            m_resource	= resource;

			m_JID		= buildJid(m_user, m_server, m_resource);
		}

		private string buildJid(string user, string server, string resource)
		{			
			StringBuilder sb = new StringBuilder();
			if (user != null)
			{
				sb.Append(user);
				sb.Append("@");
			}
			sb.Append(server);
			if (resource != null)
			{
				sb.Append("/");
				sb.Append(resource);
			}
			return sb.ToString();
		}
        
		public override string ToString()
		{
			return m_JID;
		}
				
		/// <summary>
		/// Only the User.
		/// </summary>
        public string User
		{
			get
			{				
				return m_user;
			}
			set
			{				
				m_user = value;
				m_JID = buildJid(m_user, m_server, m_resource);
			}
		}

		/// <summary>
		/// Only Server
		/// </summary>
        public string Server
		{
			get
			{
				return m_server;
			}
			set 
			{				
				m_server = value;
				m_JID = buildJid(m_user, m_server, m_resource);
			}
		}

		/// <summary>
		/// Only the Resource field.
		/// null for none
		/// </summary>        
        public string Resource
		{
			get
			{				
				return m_resource;
			}
			set 
			{			
				m_resource = value;
				m_JID = buildJid(m_user, m_server, m_resource);
			}
		}

		/// <summary>
		/// The Bare Jid only (user@server).
		/// </summary>		
        public string Bare
		{
			get
			{				
				return buildJid(m_user, m_server, null);
			}
        }

        #region << Overrides >>
        /// <summary>
        /// This compares the full Jid by default
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            return Equals(obj, new FullJidComparer());
        }

        public override int GetHashCode()
        {
            int hcode = 0;
            if (m_user  !=null)
                hcode ^= m_user.GetHashCode();

            if (m_server != null)
                hcode ^= m_server.GetHashCode();

            if (m_resource != null)
                hcode ^= m_resource.GetHashCode();
            
            return hcode;
        }
        #endregion

        public bool Equals(object other, System.Collections.IComparer comparer)
		{
			if (comparer.Compare(other, this) == 0) 
				return true;
			else
				return false;           
		}

        #region IComparable Members
        public int CompareTo(object obj)
        {
            if (obj is Jid)
            {
                Jid jid = obj as Jid;
                FullJidComparer comparer = new FullJidComparer();
                return comparer.Compare(obj, this);                 
            }
            throw new ArgumentException("object is not a Jid");    
        }
        #endregion
   
#if NET_2 || CF_2    
        #region IEquatable<Jid> Members
        public bool Equals(Jid other)
        {
            FullJidComparer comparer = new FullJidComparer();
            if (comparer.Compare(other, this) == 0)
                return true;
            else
                return false;            
        }
        #endregion
#endif


    }
}